package com.dragon.codefx.controller;

import com.dragon.codefx.constant.FieldTypeEnum;
import com.dragon.codefx.constant.FrontDefaultEnum;
import com.dragon.codefx.constant.IgnoreField;
import com.dragon.codefx.dataBase.controller.bo.GenerateBO;
import com.dragon.codefx.dataBase.controller.dto.GenerateDTO;
import com.dragon.codefx.dataBase.entity.DatabaseConfigEntity;
import com.dragon.codefx.dataBase.entity.SchemaTableConfigEntity;
import com.dragon.codefx.dataBase.entity.TableSearchConfigEntity;
import com.dragon.codefx.dataBase.service.DatabaseConfigService;
import com.dragon.codefx.dataBase.service.SchemaTableConfigService;
import com.dragon.codefx.dataBase.service.TableSearchConfigService;
import com.dragon.codefx.service.ApplicationExitService;
import com.dragon.codefx.service.ZipFileGeneratorService;
import com.dragon.codefx.utils.ColumnUtils;
import com.dragon.codefx.utils.FileDownloader;
import com.dragon.codefx.utils.GenerateUtil;
import com.dragon.config.exception.exception.GlobalException;
import com.dragon.field.FieldUtil;
import javafx.application.Platform;
import javafx.fxml.FXML;
import javafx.scene.control.*;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.DirectoryChooser;
import javafx.stage.Stage;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.awt.Desktop;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.util.*;

/**
 * 主页面
 *
 * @author lsc
 * @since 2025/9/26 09:26
 **/
@Component
public class MainViewController {
    @Resource
    private DatabaseConfigService databaseConfigService;
    @Resource
    private SchemaTableConfigService schemaTableConfigService;
    @Resource
    private TableSearchConfigService tableSearchConfigService;

    @Autowired
    private ApplicationExitService applicationExitService;

    @Autowired
    private ZipFileGeneratorService zipFileGeneratorService;

    @FXML
    private Label downloadStatusLabel;

    // Loading 相关组件
    @FXML
    private VBox loadingContainer;

    @FXML
    private ProgressIndicator loadingIndicator;

    @FXML
    private Label loadingLabel;

    @FXML
    private ProgressBar progressBar;

    @FXML
    private HBox buttonContainer;

    // 按钮组件
    @FXML
    private Button sampleCodeBtn;

    @FXML
    private Button projectTemplateBtn;

    @FXML
    private Button logFilesBtn;

    @FXML
    protected void close() {
        applicationExitService.exitApplication();
    }

    /**
     * 显示Loading状态
     */
    private void showLoading(String message) {
        showLoading(message, false);
    }

    /**
     * 显示Loading状态
     *
     * @param message      加载消息
     * @param showProgress 是否显示进度条
     */
    private void showLoading(String message, boolean showProgress) {
        Platform.runLater(() -> {
            loadingLabel.setText(message);
            loadingContainer.setVisible(true);
            loadingContainer.setManaged(true);

            // 进度条控制
            progressBar.setVisible(showProgress);
            progressBar.setManaged(showProgress);
            if (showProgress) {
                progressBar.setProgress(0.0);
            }

            // 禁用所有按钮
            setButtonsDisabled(true);

            downloadStatusLabel.setText("正在处理...");
        });
    }

    /**
     * 更新进度
     */
    private void updateProgress(double progress, String message) {
        Platform.runLater(() -> {
            if (progressBar.isVisible()) {
                progressBar.setProgress(progress);
            }
            if (message != null) {
                loadingLabel.setText(message);
            }
        });
    }

    /**
     * 隐藏Loading状态
     */
    private void hideLoading() {
        Platform.runLater(() -> {
            loadingContainer.setVisible(false);
            loadingContainer.setManaged(false);

            // 启用所有按钮
            setButtonsDisabled(false);
        });
    }

    /**
     * 设置按钮禁用/启用状态
     */
    private void setButtonsDisabled(boolean disabled) {
        sampleCodeBtn.setDisable(disabled);
        projectTemplateBtn.setDisable(disabled);
        logFilesBtn.setDisable(disabled);
    }

    @FXML
    protected void downloadSampleCode() {
        showLoading("正在生成示例代码...");

        new Thread(() -> {
            try {
                // 模拟一些处理时间
                GenerateDTO generateDTO = new GenerateDTO();
                generateDTO.setDataBaseId(1);
                generateDTO.setSchemaName("smartsite");
                generateDTO.setTableName("db_camera_video");
                GenerateBO generateBO = getGenerateBO(generateDTO);
                File generate = GenerateUtil.generate(generateBO);
                Platform.runLater(() -> {
                    hideLoading();
                    saveFileToUserLocation(generate, generateDTO.getTableName());
                    FileDownloader.deleteFolder(generate.getParentFile());
                });
            } catch (Exception e) {
                Platform.runLater(() -> {
                    hideLoading();
                    downloadStatusLabel.setText("下载失败: " + e.getMessage());
                    showErrorDialog("下载失败", "生成示例代码失败: " + e.getMessage());
                });
            }
        }).start();
    }

    @FXML
    protected void downloadProjectTemplate() {
        // 弹出对话框让用户输入项目名称
        TextInputDialog dialog = new TextInputDialog("MyProject");
        dialog.setTitle("项目模板");
        dialog.setHeaderText("创建项目模板");
        dialog.setContentText("请输入项目名称:");

        Optional<String> result = dialog.showAndWait();
        if (result.isPresent() && !result.get().trim().isEmpty()) {
            String projectName = result.get().trim();
            showLoading("正在生成项目模板: " + projectName + "...", true);

            new Thread(() -> {
                try {
                    // 模拟分步骤进度
                    updateProgress(0.1, "初始化项目结构...");
                    Thread.sleep(300);

                    updateProgress(0.3, "生成主类文件...");
                    Thread.sleep(400);

                    updateProgress(0.5, "生成控制器文件...");
                    Thread.sleep(300);

                    updateProgress(0.7, "生成配置文件...");
                    Thread.sleep(400);

                    updateProgress(0.9, "打包ZIP文件...");

                    File zipFile = zipFileGeneratorService.generateProjectTemplateZip(projectName);

                    updateProgress(1.0, "生成完成！");
                    Thread.sleep(200);

                    Platform.runLater(() -> {
                        hideLoading();
                        saveFileToUserLocation(zipFile, projectName + "项目模板");
                        downloadStatusLabel.setText("项目模板下载完成！");
                    });
                } catch (Exception e) {
                    Platform.runLater(() -> {
                        hideLoading();
                        downloadStatusLabel.setText("下载失败: " + e.getMessage());
                        showErrorDialog("下载失败", "生成项目模板失败: " + e.getMessage());
                    });
                }
            }).start();
        }
    }

    @FXML
    protected void downloadLogFiles() {
        showLoading("正在生成日志文件...");

        new Thread(() -> {
            try {
                // 模拟一些处理时间
                Thread.sleep(800);

                File zipFile = zipFileGeneratorService.generateLogFilesZip();
                Platform.runLater(() -> {
                    hideLoading();
                    saveFileToUserLocation(zipFile, "日志文件包");
                    downloadStatusLabel.setText("日志文件下载完成！");
                });
            } catch (Exception e) {
                Platform.runLater(() -> {
                    hideLoading();
                    downloadStatusLabel.setText("下载失败: " + e.getMessage());
                    showErrorDialog("下载失败", "生成日志文件失败: " + e.getMessage());
                });
            }
        }).start();
    }

    /**
     * 保存文件到用户选择的位置
     */
    private void saveFileToUserLocation(File sourceFile, String description) {
        DirectoryChooser directoryChooser = new DirectoryChooser();
        directoryChooser.setTitle("选择保存位置 - " + description);
        directoryChooser.setInitialDirectory(new File(System.getProperty("user.home", ".")));

        Stage currentStage = (Stage) downloadStatusLabel.getScene().getWindow();
        File selectedDirectory = directoryChooser.showDialog(currentStage);

        if (selectedDirectory != null) {
            try {
                File targetFile = new File(selectedDirectory, sourceFile.getName());
                Files.copy(sourceFile.toPath(), targetFile.toPath(), StandardCopyOption.REPLACE_EXISTING);

                // 删除临时文件
                sourceFile.delete();

                // 显示成功消息并询问是否打开文件夹
                ButtonType open = new ButtonType("打开", ButtonBar.ButtonData.OK_DONE);
                ButtonType close = new ButtonType("关闭", ButtonBar.ButtonData.CANCEL_CLOSE);
                Alert successAlert = new Alert(Alert.AlertType.INFORMATION,"",open, close);
                successAlert.setTitle("下载完成");
                successAlert.setHeaderText(description + "下载成功！");
                successAlert.setContentText("文件已保存到: " + targetFile.getAbsolutePath());
                Optional<ButtonType> result = successAlert.showAndWait();
                if (result.isPresent() && result.get() == open) {
                    openFileInExplorer(selectedDirectory);
                }
            } catch (IOException e) {
                showErrorDialog("保存失败", "无法保存文件: " + e.getMessage());
            }
        }
    }

    /**
     * 在文件管理器中打开文件夹
     */
    private void openFileInExplorer(File directory) {
        try {
            if (Desktop.isDesktopSupported()) {
                Desktop.getDesktop().open(directory);
            }
        } catch (IOException e) {
            showErrorDialog("打开文件夹失败", "无法打开文件夹: " + e.getMessage());
        }
    }

    /**
     * 显示错误对话框
     */
    private void showErrorDialog(String title, String message) {
        Alert alert = new Alert(Alert.AlertType.ERROR);
        alert.setTitle(title);
        alert.setHeaderText(null);
        alert.setContentText(message);
        alert.showAndWait();
    }

    @NotNull
    private GenerateBO getGenerateBO(GenerateDTO generateDTO) {
        DatabaseConfigEntity entity = databaseConfigService.findById(generateDTO.getDataBaseId());
        if (ObjectUtils.isEmpty(entity)) {
            throw new GlobalException("数据库连接不存在");
        }
        SchemaTableConfigEntity tableConfig = schemaTableConfigService.findOne(generateDTO.getSchemaName(), generateDTO.getTableName());
        if (ObjectUtils.isEmpty(entity.getUrl())) {
            throw new GlobalException("表配置不存在，请先配置");
        }
        List<TableSearchConfigEntity> searchConfigs = tableSearchConfigService.findBySchemaAndTable(generateDTO.getSchemaName(), generateDTO.getTableName());

        GenerateBO.GenerateInfo generateInfo = GenerateBO.GenerateInfo.builder()
                .author(tableConfig.getAuthor())
                .tablePrefix(tableConfig.getTablePrefix())
                .generateXml(tableConfig.getGeneraXml() == 1)
                .basePackage(tableConfig.getBasePackage())
                .tableName(tableConfig.getTableName())
                .tableComment(tableConfig.getTableComment())
                .schemaName(tableConfig.getSchemaName())
                .generateMethod(tableConfig.getGenerateMethod())
                .build();
        GenerateBO generateBO = GenerateBO.builder()
                .generateInfo(generateInfo)
                .build();

        List<GenerateBO.ColumnInfo> tableColumns = new ArrayList<>();

        List<String> ignoreField;
        if (StringUtils.isBlank(tableConfig.getParentFields())) {
            ignoreField = IgnoreField.getValues();
        } else {
            String[] split = tableConfig.getParentFields().split(",");
            ignoreField = new ArrayList<>(Arrays.asList(split));
        }
        Map<String, GenerateBO.SearchInfo> infoMap = toMap(searchConfigs);
        List<Map<String, Object>> columns = ColumnUtils.columnList(entity, generateInfo.getSchemaName(), generateInfo.getTableName());
        for (Map<String, Object> tableColumn : columns) {
            String column = tableColumn.get("column_name").toString();
            String fieldName = FieldUtil.underlineToHump(column);
            String comment = tableColumn.get("column_comment").toString();
            GenerateBO.ColumnInfo columnInfo = GenerateBO.ColumnInfo.builder()
                    .columnComment(StringUtils.isEmpty(comment) ? column : comment)
                    .columnName(column)
                    .fieldType(FieldTypeEnum.getClassType(tableColumn.get("data_type").toString()))
                    .frontType(FieldTypeEnum.getFrontType(tableColumn.get("data_type").toString()))
                    .frontDefault(FrontDefaultEnum.getDefaultValue(FieldTypeEnum.getFrontType(tableColumn.get("data_type").toString())))
                    .fieldName(fieldName)
                    .searchInfo(infoMap.get(fieldName))
                    .keyFlag(StringUtils.isNotBlank(tableColumn.get("column_key").toString()) && "PRI".equals(tableColumn.get("column_key").toString()))
                    .isParent(ignoreField.contains(column))
                    .build();

            tableColumns.add(columnInfo);
        }
        generateBO.getGenerateInfo().setTableColumns(tableColumns);
        List<GenerateBO.ParentInfo> parentsField = new ArrayList<>();
        for (String field : ignoreField) {
            GenerateBO.ParentInfo info = new GenerateBO.ParentInfo();
            info.setProperty(FieldUtil.underlineToHump(field));
            info.setColumn(field);
            parentsField.add(info);
        }
        generateBO.getGenerateInfo().setParentsField(parentsField);
        if (StringUtils.isBlank(generateBO.getGenerateInfo().getTableComment())) {
            generateBO.getGenerateInfo().setTableComment("");
        }
        return generateBO;
    }

    public Map<String, GenerateBO.SearchInfo> toMap(List<TableSearchConfigEntity> searchDTOList) {
        Map<String, GenerateBO.SearchInfo> searchDTOMap = new HashMap<>();
        for (TableSearchConfigEntity searchDTO : searchDTOList) {
            GenerateBO.SearchInfo searchInfo = GenerateBO.SearchInfo.builder()
                    .blurry(searchDTO.getBlurry())
                    .queryType(searchDTO.getQueryType())
                    .propName(searchDTO.getPropName())
                    .build();
            searchDTOMap.put(searchDTO.getFiledName(), searchInfo);
        }
        return searchDTOMap;
    }

}
